#include <magic_enum/magic_enum.hpp>
#include <nlohmann/json.hpp>
#include <string>

#include "asio_driver/io/gpio.hpp"
#include "event.hpp"
#include "factory.hpp"
#include "global.hpp"

class Gpio : public Event
{
  private:
    enum class Trigger
    {
        Rising,
        Falling,
        Both,
        None
    };
    Trigger trigger;
    int pin;
    AD::GPIO io;
    bool levelT1;
    bool levelT2;

  public:
    Gpio(const nlohmann::json &j) : Event(j), io(Global::Instance().asio_context)
    {
        auto ret = magic_enum::enum_cast<Gpio::Trigger>(j.at("trigger").get<std::string>());
        trigger = ret.has_value() ? ret.value() : Gpio::Trigger::None;
        j.at("pin").get_to(pin);
        io.Open(pin);
        io.SetWorkMode(AD::GPIO::GPIOMode::Input);
    }

    virtual bool CheckAct() override
    {
        bool is_act = false;
        if (!io.IsOpen())
        {
            spdlog::error("GPIO is still not open");
            return false;
        }
        bool level = io.Read();
        if (levelT1 != levelT2 && level == levelT2)
        {
            if (trigger == Gpio::Trigger::Rising && level)
            {
                is_act = true;
            }
            else if (trigger == Gpio::Trigger::Falling && !level)
            {
                is_act = true;
            }
        }
        levelT1 = levelT2;
        levelT2 = level;
        return is_act;
    }
};
static Factory<Event>::Register<Gpio> reg("gpio");